﻿using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Data;
using System.Windows.Navigation;
using System.Xml;
using GpgApi;
using WgpgCore;

namespace WgpgGUI
{
    public partial class DialogAboutWgpg : Window
    {
        private const String m_propertyNameTitle = "Title";
        private const String m_propertyNameDescription = "Description";
        private const String m_propertyNameProduct = "Product";
        private const String m_propertyNameCopyright = "Copyright";
        private const String m_propertyNameCompany = "Company";

        private const String m_xPathRoot = "ApplicationInfo/";
        private const String m_xPathTitle = m_xPathRoot + m_propertyNameTitle;
        private const String m_xPathVersion = m_xPathRoot + "Version";
        private const String m_xPathDescription = m_xPathRoot + m_propertyNameDescription;
        private const String m_xPathProduct = m_xPathRoot + m_propertyNameProduct;
        private const String m_xPathCopyright = m_xPathRoot + m_propertyNameCopyright;
        private const String m_xPathCompany = m_xPathRoot + m_propertyNameCompany;
        private const String m_xPathLink = m_xPathRoot + "Link";
        private const String m_xPathLinkUri = m_xPathRoot + "Link/@Uri";

        private XmlDocument m_xmlDoc = null;

        public DialogAboutWgpg(Window owner)
        {
            Owner = owner;
            InitializeComponent();
        }

        protected override void OnSourceInitialized(EventArgs e)
        {
            Utils.RemoveIcon(this);
        }

        private void Hyperlink_RequestNavigate(Object sender, RequestNavigateEventArgs e)
        {
            if (e.Uri != null && !String.IsNullOrEmpty(e.Uri.OriginalString))
            {
                Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
                e.Handled = true;
            }
        }

        /// <summary>
        /// Gets the title property, which is displayed in the About dialogs window title.
        /// </summary>
        public String ProductTitle
        {
            get
            {
                String result = CalculatePropertyValue<AssemblyTitleAttribute>(m_propertyNameTitle, m_xPathTitle);
                if (String.IsNullOrEmpty(result))
                {
                    // otherwise, just get the name of the assembly itself.
                    result = Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase);
                }
                return result;
            }
        }

        /// <summary>
        /// Gets the application's version information to show.
        /// </summary>
        public String Version
        {
            get
            {
                String result = String.Empty;
                // first, try to get the version string from the assembly.
                Version assemblyversion = Assembly.GetExecutingAssembly().GetName().Version;
                if (assemblyversion != null)
                    result = assemblyversion.ToString();
                else
                {
                    // if that fails, try to get the version from a resource in the Application.
                    result = GetLogicalResourceString(m_xPathVersion);
                }
                return result;
            }
        }

        public String GpgVersion
        {
            get
            {
                GpgVersion tmp = new GpgVersion();
                tmp.Execute();
                return tmp.Version.ToString();
            }
        }

        /// <summary>
        /// Gets the description about the application.
        /// </summary>
        public String Description
        {
            get { return CalculatePropertyValue<AssemblyDescriptionAttribute>(m_propertyNameDescription, m_xPathDescription); }
        }

        /// <summary>
        ///  Gets the product's full name.
        /// </summary>
        public String Product
        {
            get { return CalculatePropertyValue<AssemblyProductAttribute>(m_propertyNameProduct, m_xPathProduct); }
        }

        /// <summary>
        /// Gets the copyright information for the product.
        /// </summary>
        public String Copyright
        {
            get { return CalculatePropertyValue<AssemblyCopyrightAttribute>(m_propertyNameCopyright, m_xPathCopyright); }
        }

        /// <summary>
        /// Gets the product's company name.
        /// </summary>
        public String Company
        {
            get { return CalculatePropertyValue<AssemblyCompanyAttribute>(m_propertyNameCompany, m_xPathCompany); }
        }

        /// <summary>
        /// Gets the link text to display in the About dialog.
        /// </summary>
        public String LinkText
        {
            get { return GetLogicalResourceString(m_xPathLink); }
        }

        /// <summary>
        /// Gets the link uri that is the navigation target of the link.
        /// </summary>
        public String LinkUri
        {
            get { return GetLogicalResourceString(m_xPathLinkUri); }
        }

        /// <summary>
        /// Gets the specified property value either from a specific attribute, or from a resource dictionary.
        /// </summary>
        /// <typeparam name="T">Attribute type that we're trying to retrieve.</typeparam>
        /// <param name="propertyName">Property name to use on the attribute.</param>
        /// <param name="xpathQuery">XPath to the element in the XML data resource.</param>
        /// <returns>The resulting string to use for a property.
        /// Returns null if no data could be retrieved.</returns>
        private String CalculatePropertyValue<T>(String propertyName, String xpathQuery)
        {
            String result = String.Empty;

            // first, try to get the property value from an attribute.
            Object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(T), false);
            if (attributes.Length > 0)
            {
                T attrib = (T)attributes[0];
                PropertyInfo property = attrib.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
                if (property != null)
                    result = property.GetValue(attributes[0], null) as String;
            }

            // if the attribute wasn't found or it did not have a value, then look in an xml resource.
            if (String.IsNullOrEmpty(result))
            {
                // if that fails, try to get it from a resource.
                result = GetLogicalResourceString(xpathQuery);
            }

            return result;
        }

        /// <summary>
        /// Gets the XmlDataProvider's document from the resource dictionary.
        /// </summary>
        protected virtual XmlDocument ResourceXmlDocument
        {
            get
            {
                if (m_xmlDoc == null)
                {
                    // if we haven't already found the resource XmlDocument, then try to find it.
                    XmlDataProvider provider = TryFindResource("aboutProvider") as XmlDataProvider;
                    if (provider != null)
                    {
                        // save away the XmlDocument, so we don't have to get it multiple times.
                        m_xmlDoc = provider.Document;
                    }
                }
                return m_xmlDoc;
            }
        }

        /// <summary>
        /// Gets the specified data element from the XmlDataProvider in the resource dictionary.
        /// </summary>
        /// <param name="xpathQuery">An XPath query to the XML element to retrieve.</param>
        /// <returns>The resulting string value for the specified XML element. 
        /// Returns empty string if resource element couldn't be found.</returns>
        protected virtual String GetLogicalResourceString(String xpathQuery)
        {
            String result = String.Empty;
            // get the About xml information from the resources.
            XmlDocument doc = ResourceXmlDocument;
            if (doc != null)
            {
                // if we found the XmlDocument, then look for the specified data. 
                XmlNode node = doc.SelectSingleNode(xpathQuery);
                if (node != null)
                {
                    if (node is XmlAttribute)
                    {
                        // only an XmlAttribute has a Value set.
                        result = node.Value;
                    }
                    else
                    {
                        // otherwise, need to just return the inner text.
                        result = node.InnerText;
                    }
                }
            }
            return result;
        }
    }
}
